package com.wg.core.thread.scheduler;

import com.wg.core.lang.IDisposable;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicReference;

public class TimerAction implements IDisposable {
    private final long firstIntervalInMs;
    private final long intervalInMs;
    private final ISchedulerRegistry registry;
    private final AtomicReference<ScheduledFuture<?>> atomicReference = new AtomicReference<>();
    private volatile boolean isCancelled;
    private volatile Runnable task;

    public TimerAction(ISchedulerRegistry registry, Runnable task, long firstIntervalInMs, long intervalInMs) {
        this.firstIntervalInMs = firstIntervalInMs;
        this.intervalInMs = intervalInMs;
        this.registry = registry;
        this.task = task;
    }

    @Override
    public void dispose() {
        if (this.isCancelled) {
            return;
        }

        this.isCancelled = true;
        this.task = null;
        ScheduledFuture<?> future = atomicReference.getAndSet(null);
        if (future != null) {
            future.cancel(false);
        }
    }

    public void executeOnFiberThread() {
        if (this.isCancelled) {
            return;
        }

        Runnable currentTask = this.task;
        if (currentTask != null) {
            currentTask.run();
        }
    }

    public void executeOnTimerThread() {
        if (this.isCancelled) {
            return;
        }

        if (this.intervalInMs == -1L) {
            // 移除前再次确认状态（双重检查）
            if (!this.isCancelled) {
                this.registry.remove(this);
                ScheduledFuture<?> future = this.atomicReference.getAndSet(null);
                if (future != null) {
                    future.cancel(false);
                }
            }
        }
        this.registry.enqueue(this::executeOnFiberThread);
    }

    public void schedule() {
        if (this.isCancelled) {
            return;
        }
        
        ScheduledFuture<?> future;
        if (this.intervalInMs != -1L) {
            future = this.registry.getThreadPool().scheduleAtFixedRate(this::executeOnTimerThread, firstIntervalInMs,
                    intervalInMs);
        } else {
            future = this.registry.getThreadPool().schedule(this::executeOnTimerThread, firstIntervalInMs);
        }
        atomicReference.set(future);
    }
}
